package com.liwen.service.pool;

import com.jcraft.jsch.*;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: li.rui
 * @time: 2018-03-15 12:19
 * @description:
 */
public abstract class AbstractFtpClient implements FtpClient {
    private Logger log = LoggerFactory.getLogger(this.getClass());
    private String host;
    private String user;
    private String pwd;
    private int port;
    private JSch jsch;

    public String getHost() {
        return host;
    }

    public String getUser() {
        return user;
    }

    public String getPwd() {
        return pwd;
    }

    public int getPort() {
        return port;
    }

    public JSch getJsch() {
        return jsch;
    }

    /**
     * 构造方法
     *
     * @param host
     * @param user
     * @param pwd
     * @param port
     */
    public AbstractFtpClient(String host, String user, String pwd, int port) {
        this.host = host;
        this.user = user;
        this.pwd = pwd;
        this.port = port;
        this.jsch = new JSch();
    }

    /**
     * 获取session
     *
     * @return
     */
    @Override
    public Session session() throws Exception {
        Session session = jsch.getSession(user, host, port);
        session.setConfig("StrictHostKeyChecking", "no");//设置第一次登陆的时候提示，可选值：(ask | yes | no)
        if (!StringUtils.isEmpty(pwd))
            session.setPassword(pwd);//设置登录主机的密码
        session.connect();
        return session;
    }

    /**
     * SFTP
     *
     * @return
     */
    public ChannelSftp sftp(Session session) throws Exception {
        Channel channel = session.openChannel("sftp");
        channel.connect();
        return (ChannelSftp) channel;
    }

    /**
     * 下载文件
     *
     * @param remotePath 远程文件路径
     * @return
     */
    @Override
    public byte[] download(String remotePath) {
        Session session = null;
        ChannelSftp sftp = null;
        try {
            session = session();
            sftp = sftp(session);
            InputStream is = sftp.get(remotePath);

            return afterDownload(IOUtils.toByteArray(is));
        } catch (Exception e) {
            log.error("download-err=remotePath:{},msg:{}", remotePath, e.getMessage());
            return null;
        } finally {
            if (null != sftp) {
                sftp.quit();
                sftp.disconnect();
            }
            if (null != session)
                session.disconnect();
        }
    }

    /**
     * 批量下载
     *
     * @param remotePaths
     * @return
     */
    @Override
    public List<byte[]> download(List<String> remotePaths) {
        Session session = null;
        ChannelSftp sftp = null;
        try {
            session = session();
            sftp = sftp(session);
            List<byte[]> list = new ArrayList<>();
            for (String remotePath : remotePaths) {
                InputStream is = sftp.get(remotePath);
                list.add(afterDownload(IOUtils.toByteArray(is)));
            }
            return list;
        } catch (Exception e) {
            log.error("download-err=remotePath:{},msg:{}", remotePaths, e.getMessage());
            return null;
        } finally {
            if (null != sftp) {
                sftp.quit();
                sftp.disconnect();
            }
            if (null != session)
                session.disconnect();
        }
    }

    /**
     * 处理下载的文件
     *
     * @param bytes
     * @return
     */
    protected byte[] afterDownload(byte[] bytes) {
        return bytes;
    }

    /**
     * 处理上传的文件
     *
     * @param bytes
     * @return
     */
    protected String beforeUpload(byte[] bytes) {
        try {
            return new String(bytes, "utf-8");
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    /**
     * 上传文件
     *
     * @param remoteDir  远程文件夹
     * @param remoteName 远程文件名
     * @param content    上传的内容
     * @return
     */
    @Override
    public boolean upload(String remoteDir, String remoteName, byte[] content) {
        Session session = null;
        ChannelSftp sftp = null;
        try {
            session = session();
            sftp = sftp(session);
            String str = beforeUpload(content);
            if (null == str) {
                return false;
            }
            InputStream is = IOUtils.toInputStream(str, "utf-8");
            createRemoteDir(sftp, remoteDir);
            sftp.put(is, remoteDir + "/" + remoteName);
            return true;
        } catch (Exception e) {
            log.error("upload-err=remoteDir:{},remoteName:{},msg:{}", remoteDir, remoteName, e.getMessage());
            return false;
        } finally {
            if (null != sftp) {
                sftp.quit();
                sftp.disconnect();
            }
            if (null != session)
                session.disconnect();

        }
    }

    /**
     * 判断文件夹是否存在
     *
     * @param sftp
     * @param remoteDir
     * @return
     */
    private boolean dirExist(ChannelSftp sftp, String remoteDir) {
        try {
            SftpATTRS attrs = sftp.lstat(remoteDir);
            return attrs.isDir();
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 创建远程文件夹
     *
     * @param sftp
     * @param remoteDir
     * @throws Exception
     */
    private void createRemoteDir(ChannelSftp sftp, String remoteDir) throws Exception {
        if (dirExist(sftp, remoteDir)) {
            sftp.cd(remoteDir);
            return;
        }
        String[] str = remoteDir.split("/");
        StringBuilder dirPath = new StringBuilder("/");
        for (String path : str) {
            if (!"".equals(path)) {
                dirPath.append(path).append("/");
                if (dirExist(sftp, dirPath.toString())) {
                    sftp.cd(dirPath.toString());
                } else {
                    sftp.mkdir(dirPath.toString());
                    sftp.cd(dirPath.toString());
                }
            }
        }
        sftp.cd(remoteDir);
    }


}
